﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using MP3Ganizer.BusinessObject.Infos;
using System.IO;
using TagLib;
using System.Collections.ObjectModel;
using MP3Ganizer.BusinessObject.Services.Common;

namespace MP3Ganizer.BusinessObject.Services.IO
{
    public class FileService : MP3Ganizer.BusinessObject.Services.IO.IFileService
    {
        private string[] MUSIC_MANAGED_TYPE = new string[] {"mp3", "wma"};
        private string[] IMG_MANAGED_TYPE = new string[] { "jpeg", "jpg", "bmp", "gif" };

        private Dictionary<string, string[]> _imagesStates;



        public IServiceResult GetMP3InfosFromDirectory(string directory, List<MP3Infos> list)
        {
            if (list == null)
                return new ServiceFailure("Erreur interne du service.");
            try
            {
                _imagesStates = new Dictionary<string, string[]>();
                IEnumerable<string> files = MUSIC_MANAGED_TYPE.SelectMany(t => Directory.EnumerateFiles(directory, string.Format("*.{0}", t), SearchOption.AllDirectories));
                files.ToList().ForEach(file => list.Add(CreateInfoFromFile(file)));
            }
            catch (Exception e)
            {
                return new ServiceFailure("Erreur lors de la chargement du répertoire", e.Message);

            }
            return new ServiceSuccess();

        }
        public IEnumerable<MP3Infos> GetMP3InfosFromDirectory(string directory)
        {
            IEnumerable<string> files = MUSIC_MANAGED_TYPE.SelectMany(t => Directory.EnumerateFiles(directory, string.Format("*.{0}", t), SearchOption.AllDirectories));
            return files.Select(file => CreateInfoFromFile(file));
        }
        private MP3Infos CreateInfoFromFile(string file)
        {
            try
            {
                var tagfile = TagLib.File.Create(file);

                IEnumerable<string> artists = tagfile.Tag.Performers.AsEnumerable().OrderBy(a => a);
                if (string.IsNullOrEmpty(tagfile.Tag.FirstPerformer) && !string.IsNullOrEmpty(tagfile.Tag.FirstAlbumArtist))
                    artists = tagfile.Tag.AlbumArtists.AsEnumerable().OrderBy(a => a);
                if (artists == null)
                    artists = DefaultValues.Artistes;

                string album = tagfile.Tag.Album;
                if (string.IsNullOrEmpty(album ))
                    album = DefaultValues.Album;

                string title = tagfile.Tag.Title;
                if (string.IsNullOrEmpty(title))
                    title = System.IO.Path.GetFileNameWithoutExtension(file);
                if (string.IsNullOrEmpty(title))
                    title = DefaultValues.Title;

                int track = (int)tagfile.Tag.Track;

                string[] images = GetImagesFromFileDirectory(file);

                return new MP3Infos(artists, album, title, track, file, images);
            }
            catch
            {
                return new MP3Infos(DefaultValues.Artistes, DefaultValues.Album, DefaultValues.Title, 0, file, DefaultValues.Images); 
            }
        }

        private string[] GetImagesFromFileDirectory(string file)
        {
            var directory = new FileInfo(file).Directory;

            if (_imagesStates.ContainsKey(directory.FullName))
                return _imagesStates[directory.FullName];
            else
            {
                string[] images = new string[0];
                IMG_MANAGED_TYPE.ToList().ForEach(item => images = images.Concat(directory.GetFiles(string.Format("*.{0}", item)).Select(f => f.FullName)).ToArray());
                _imagesStates.Add(directory.FullName, images);
                return images;
            }
        }
        public bool TryToApplySettings(IEnumerable<MP3Infos> infos, string directory, out IEnumerable<MP3Infos> withProblem)
        {
            IEnumerable<MP3Infos> mayHaveProblem = new MP3Infos[0].AsEnumerable();
            IEnumerable<MP3Infos> modified = new MP3Infos[0].AsEnumerable();

            bool success = infos.All(info => TryToMove(info, directory, modified, mayHaveProblem));

            success = success && modified.All(info => TryToUpdate(info, modified, mayHaveProblem));

            withProblem = mayHaveProblem;

            return success;
        }
        private bool TryToUpdate(MP3Infos info, IEnumerable<MP3Infos> modified, IEnumerable<MP3Infos> mayHaveProblem)
        {
            try
            {
                var tagFile = TagLib.File.Create(info.SourcePath);

                tagFile.Tag.Album = info.Album;
                tagFile.Tag.Performers = info.Artists.ToArray();
                tagFile.Tag.Title = info.Title;
                tagFile.Tag.Track = (uint)info.TrackNumber;
                tagFile.Save();
                
                modified.Concat(new MP3Infos[1] { info }.AsEnumerable());
                return true;
            }
            catch
            {
                mayHaveProblem.Concat(new MP3Infos[1] { info }.AsEnumerable());
                return false;
            }   
        }
        private bool TryToMove(MP3Infos info, string directory, IEnumerable<MP3Infos> modified, IEnumerable<MP3Infos> mayHaveProblem)
        {
            try
            {
                string fileName = string.Format("{1} - {0}", info.Title, info.TrackNumber);
                string filePath = System.IO.Path.Combine(directory, fileName);

                System.IO.File.Move(info.SourcePath, filePath);
                //System.IO.File.Delete(info.SourcePath);

                modified.Concat(new MP3Infos[1] { info.ChangeSourcePath(filePath)}.AsEnumerable());

                return true;
            }
            catch
            {
                mayHaveProblem.Concat(new MP3Infos[1] { info }.AsEnumerable());
                return false;
            }   
        }

        //public string CopyToDestination(string sourcePath, string destinationPath)
        //{
        //    string msg = string.Empty;
        //    try
        //    {
        //        FileInfo destinationInfo = new FileInfo(destinationPath);

        //        if (!System.IO.Directory.Exists(destinationInfo.DirectoryName))
        //            System.IO.Directory.CreateDirectory(destinationInfo.DirectoryName);
        //        if (System.IO.File.Exists(destinationPath))
        //            System.IO.File.Delete(destinationPath);
        //        if (!System.IO.File.Exists(destinationPath) && System.IO.Directory.Exists(destinationInfo.DirectoryName) && System.IO.File.Exists(sourcePath))
        //        {
        //            System.IO.File.Copy(sourcePath, destinationPath);
        //            Delete(sourcePath);
        //        }
        //    }
        //    catch (Exception e)
        //    {
        //        msg = e.Message;
        //    }
        //    return msg;
        //}

        //private void Delete(string sourcePath)
        //{
            
        //        System.IO.File.Delete(sourcePath);
            
        //}

        //public void CleanEmptyDirectories(string sourceDir)
        //{
        //    System.IO.DirectoryInfo dirInfo = new DirectoryInfo(sourceDir);
        //    List<DirectoryInfo> subDirectories = dirInfo.GetDirectories("*", SearchOption.TopDirectoryOnly).ToList<DirectoryInfo>();
        //    subDirectories.ForEach(d =>
        //    {
        //        List<FileInfo> inutils = d.GetFiles("desktop.ini", SearchOption.AllDirectories).ToList<FileInfo>();
        //        inutils.AddRange(d.GetFiles("Thumbs.db", SearchOption.AllDirectories).ToList<FileInfo>());
        //        if (inutils.Count > 0)
        //            inutils.ForEach(f => f.Delete());
        //        if (d.GetFiles("*", SearchOption.AllDirectories).Count<FileInfo>() == 0)
        //            d.Delete(true);
        //    }
        //    );
        //}

        //public void GetTagsFromDirectory(ObservableCollection<object> tagFiles, string path, out int total)
        //{
        //    List<string> files = Directory.GetFiles(path, "*.*", SearchOption.AllDirectories).ToList<string>();
        //    total = files.Count;
        //    files.ForEach(x => AddTagFile(tagFiles, x));
        //}

        //private void AddTagFile(ObservableCollection<object> tagFiles, string file)
        //{
        //    try
        //    {
        //        TagLib.File f = TagLib.File.Create(file);
        //        tagFiles.Add(f);


        //    }
        //    catch
        //    {
        //        if (!file.ToLower().EndsWith(".db") && !file.ToLower().EndsWith(".ini"))
        //            tagFiles.Add(file);
        //    }
        //}

        //public string GetDestinationPathFromSource(TagLib.File file, string albumArtist, string album, string destination, string name)
        //{
        //    string path;
        //    if (file != null)
        //        path = GetDestinationPathFromSource(file, destination);
        //    else
        //        path = GetDestinationPathFromSource(albumArtist, album, destination, name);
        //    return path;

        //}
        //private string RemoveForbiddenChar(string originalStr)
        //{
        //    List<string> forbidden = (new string[11] { "\\", "/", ":", "*", "?", "\"", "<", ">", "|", ".", "_" }).ToList<string>();
        //    forbidden.ForEach(c =>
        //    {
        //        if (originalStr != null)
        //            originalStr = originalStr.Replace(c, string.Empty);
        //    }
        //    );
        //    return originalStr;
        //}
        //private string GetDestinationPathFromSource(string albumArtist, string album, string destination, string name)
        //{
        //    albumArtist = RemoveForbiddenChar(albumArtist);
        //    album = RemoveForbiddenChar(album);
        //    name = RemoveForbiddenChar(name);

        //    string destDir = string.Concat(destination, "\\");
        //    if (!string.IsNullOrEmpty(albumArtist))
        //        destDir = string.Concat(destDir, albumArtist, "\\");
        //    if (!string.IsNullOrEmpty(album))
        //        destDir = string.Concat(destDir, album, "\\");
        //    string destFile = string.Concat(destDir, name);
        //    return destFile;
        //}


        //private string GetDestinationPathFromSource(TagLib.File file, string destination)
        //{
        //    string firstAlbumArtist = RemoveForbiddenChar(file.Tag.FirstAlbumArtist);
        //    string album = RemoveForbiddenChar(file.Tag.Album);
        //    string title = file.Tag.Title != null ? file.Tag.Title.Replace('\\', '_') : "";
        //    string destFile = RemoveForbiddenChar(title);
        //    string destDir = string.Concat(destination, "\\", firstAlbumArtist, "\\", album, "\\");
        //    if (file.Tag.Track != 0)
        //        destFile = string.Concat(file.Tag.Track, " - ", destFile, ".", file.Name.Split('.').Last<string>());
        //    else
        //        destFile = string.Concat(destFile, ".", file.Name.Split('.').Last<string>());
        //    destFile = string.Concat(destDir, destFile);
        //    return destFile;
        //}
    }
}
